---
import { Icon } from '@astrojs/starlight/components';
import SidebarPersister from '@astrojs/starlight/components/SidebarPersister.astro';
import SidebarSublist from '@astrojs/starlight/components/SidebarSublist.astro';
import type { StarlightRouteData } from '@astrojs/starlight/route-data';
import { stripLeadingAndTrailingSlashes } from 'node_modules/@astrojs/starlight/utils/path';
import { allPages } from '~/content';
import { isSubPage } from '~/util/isSubPage';
import { stripLangFromSlug } from '~/util/path-utils';
import Sponsors from '../LeftSidebar/Sponsors.astro';
import TabbedContent from '../tabs/TabbedContent.astro';
import TabListItem from '../tabs/TabListItem.astro';
import TabPanel from '../tabs/TabPanel.astro';
import MobileMenuFooter from './MobileMenuFooter.astro';

const { sidebar, id } = Astro.locals.starlightRoute;

// Recursively tweaks properties of sidebar entries.
// - Adds a fallback class to entries in the sidebar that don’t exist in the current language.
// - Marks pages as “current” if they parents of pages that don’t appear in the sidebar.
type SidebarEntry = StarlightRouteData['sidebar'][number];
function markEntries(i: SidebarEntry) {
	if (i.type === 'group') {
		i.entries.forEach(markEntries);
	} else {
		const itemSlug = stripLeadingAndTrailingSlashes(i.href);
		const itemSlugWithoutLang = stripLangFromSlug(itemSlug);
		const isFallback = !allPages.some((entry) => entry.id === itemSlug);
		if (isFallback) i.attrs.class = 'fallback';
		i.isCurrent ||= isSubPage(id, itemSlugWithoutLang);
	}
}
sidebar.forEach(markEntries);

// Make sure all top-level items in the sidebar are groups.
type Group = Extract<SidebarEntry, { type: 'group' }>;
function assertGroups(sidebar: SidebarEntry[]): asserts sidebar is Group[] {
	for (const entry of sidebar) {
		if (entry.type !== 'group') {
			throw new Error('Top-level links are not permitted in the docs sidebar.');
		}
	}
}
assertGroups(sidebar);

/** Convert a group label to an `id` we can use to identify tab panels. */
// The id is prefixed to avoid clashing with existing heading IDs on the page.
const makeId = (label: string) => '__tab-' + label.toLowerCase().replaceAll(/\s+/g, '-');

/** Get the icon for a group. Update the icon names in the array to change the icons associated with a group. */
const getIcon = (index: number) =>
	(['rocket', 'open-book', 'information', 'puzzle', 'setting'] as const)[index];

/** Determine if an array of sidebar items contains the current page.  */
const isCurrent = (sidebar: SidebarEntry[]): boolean =>
	sidebar
		.map((entry) => (entry.type === 'link' ? entry.isCurrent : isCurrent(entry.entries)))
		.some((entry) => entry === true);
---

<SidebarPersister>
	<TabbedContent class="tabbed-sidebar">
		<Fragment slot="tab-list">
			{
				sidebar.map(({ label, entries }, index) => (
					<TabListItem id={makeId(label)} initial={isCurrent(entries)} class="tab-item">
						<Icon class="icon" name={getIcon(index)} /> {label}
					</TabListItem>
				))
			}
		</Fragment>
		{
			sidebar.map(({ label, entries }) => (
				<TabPanel id={makeId(label)} initial={isCurrent(entries)}>
					<SidebarSublist sublist={entries} />
				</TabPanel>
			))
		}
	</TabbedContent>
</SidebarPersister>

<div class="md:sl-hidden">
	<MobileMenuFooter />
</div>

<div class="desktop-footer sl-hidden md:sl-block">
	<Sponsors />
</div>

<style>
	/** Add "EN" to the end of sidebar items with the `fallback` class. */
	:global(.fallback)::after {
		content: 'EN';
		vertical-align: super;
		font-size: 0.75em;
		font-weight: 700;
	}

	/** Align sponsors at sidebar bottom when there is room. */
	.desktop-footer {
		margin-top: auto;
	}

	/** Always show the scrollbar gutter. */
	:global(.sidebar-pane) {
		overflow-y: scroll;
	}

	/* Styles for the custom tab switcher. */
	.tabbed-sidebar {
		/* Layout variables */
		--tab-switcher-border-width: 1px;
		--tab-switcher-padding: calc(0.25rem - var(--tab-switcher-border-width));
		--tab-item-border-radius: 0.5rem;
		--tab-switcher-border-radius: calc(
			var(--tab-item-border-radius) + var(--tab-switcher-padding) + var(--tab-switcher-border-width)
		);

		/* Color variables */
		--tab-switcher-border-color: var(--sl-color-hairline-light);
		--tab-switcher-background-color: var(--sl-color-gray-7, var(--sl-color-gray-6));
		--tab-switcher-text-color: var(--sl-color-gray-3);
		--tab-switcher-text-color--active: var(--sl-color-white);
		--tab-switcher-icon-color: var(--sl-color-gray-4);
		--tab-switcher-icon-color--active: var(--sl-color-text-accent);
		--tab-item-background-color--hover: var(--sl-color-gray-6);
		--tab-item-background-color--active: var(--sl-color-black);
	}
	/* Dark theme variations */
	:global([data-theme='dark']) .tabbed-sidebar {
		--tab-switcher-text-color: var(--sl-color-gray-2);
		--tab-switcher-icon-color: var(--sl-color-gray-3);
		--tab-item-background-color--hover: var(--sl-color-gray-5);
	}

	@media (min-width: 50rem) {
		/* Dark theme variations with the desktop sidebar visible */
		:global([data-theme='dark']) .tabbed-sidebar {
			--tab-switcher-background-color: var(--sl-color-black);
			--tab-item-background-color--hover: var(--sl-color-gray-6);
			--tab-item-background-color--active: var(--sl-color-gray-6);
		}
	}

	.tabbed-sidebar.tab-list {
		border: var(--tab-switcher-border-width) solid var(--tab-switcher-border-color);
		border-radius: var(--tab-switcher-border-radius);
		display: flex;
		flex-direction: column;
		gap: 0.25rem;
		padding: var(--tab-switcher-padding);
		background-color: var(--tab-switcher-background-color);
		margin-bottom: 1.5rem;
	}

	.tab-item :global(a) {
		border: var(--tab-switcher-border-width) solid transparent;
		border-radius: var(--tab-item-border-radius);
		display: flex;
		align-items: center;
		gap: 0.5rem;
		padding: calc(0.5rem - var(--tab-switcher-border-width));
		background-clip: padding-box;
		line-height: var(--sl-line-height-headings);
		text-decoration: none;
		color: var(--tab-switcher-text-color);
		font-weight: 600;
	}

	.tab-item :global(a:hover) {
		color: var(--tab-switcher-text-color--active);
		background-color: var(--tab-item-background-color--hover);
	}
	.tab-item :global(a[aria-selected='true']) {
		border-color: var(--tab-switcher-border-color);
		color: var(--tab-switcher-text-color--active);
		background-color: var(--tab-item-background-color--active);
	}

	.icon {
		margin: 0.25rem;
		color: var(--tab-switcher-icon-color);
	}
	.tab-item :global(a:hover) .icon {
		color: inherit;
	}
	.tab-item :global(a[aria-selected='true']) .icon {
		color: var(--tab-switcher-icon-color--active);
	}
</style>
